/*
 * Alloy Analyzer
 * Copyright (c) 2002 Massachusetts Institute of Technology
 *
 * The Alloy Analyzer is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * The Alloy Analyzer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the Alloy Analyzer; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package alloy.util;

import java.util.Enumeration;
import java.util.Vector;

import javax.swing.tree.TreeNode;

/** A {@link TreeNode} whose children are {@link DelayedValue}s of {@link TreeNode}s.
    Does not force the computation of these delayed values, until they're actually
    needed. */
public class DelayedTreeNode implements TreeNode {
    /** Optional user object associated with this node.  Returned by
	{@link #getUserObject}; also used to get a {@link String} value
	for this node. */
    private Object _userObject;

    /** Parent of this node.  Set when this node is added as child of another node. */
    private TreeNode _parent;

    /** Children of this node; may be either {@link TreeNode}s <em>or</em> {@link DelayedValue}s
	of {@link TreeNode}s. */
    private Vector _children = new Vector();

    public DelayedTreeNode(Object userObject_) {
	_userObject = userObject_;
    }

    public String toString() { return _userObject==null ? "null" : _userObject.toString(); }

    public Enumeration children() {
	for (int i=0; i<_children.size(); i++)
	    _forceChild(i);
	return _children.elements();
    }

    public int getChildCount() { return _children.size(); }
    public int getIndex(TreeNode node_) {
	for (int i=0; i<_children.size(); i++)
	    if (_children.get(i) == node_) return i;
	return -1;
    }
    
    public boolean getAllowsChildren() { return true; }
    public boolean isLeaf() { return _children.isEmpty(); }
    public TreeNode getChildAt(int i_) {
	_forceChild(i_);
	return (TreeNode)_children.get(i_);
    }

    public TreeNode getParent() { return _parent; }
    public void setParent(TreeNode parent_) { _parent = parent_; }

    public Object getUserObject() { return _userObject; }
    public void setUserObject(Object userObject_) { _userObject = userObject_; }

    public void add(Object newChild_) {
	Dbg.chk(newChild_ instanceof TreeNode ||
		newChild_ instanceof DelayedValue);
	_children.add(newChild_);
    }


    /** Force the delayed value of the given child. */
    private void _forceChild(int i_) {
	Object child = _children.get(i_);
	Dbg.chk(child);
	if (!(child instanceof TreeNode)) {
	    Dbg.chk(child instanceof DelayedValue);
	    child = ((DelayedValue)child).getValue();
	    _children.set(i_, child);
	    if (child instanceof DelayedTreeNode)
		((DelayedTreeNode)child).setParent(this);
	}
	Dbg.chk(child);
	Dbg.chk(child instanceof TreeNode);
    }
}
